-- Random seeds; first seed controls the vertex selection, second seed controls the mesh topology
plugin "ddgjs" (10.0, 5.0)

global {
    global.padding = 20.0
    global.stroke = 2.0
    global.spacing = 150.0

    global.sc_rect_stroke = 2.0
    global.edgeStroke = 1.5
    global.selectedEdgeStroke = 3.0

    global.selectedFaceColor = global.selectedColor

    global.selectedRadius = 3.6
    global.selectedThickness = 3.1

    global.selectedColor = Colors.midnightblue
    global.selectedColor2 = Colors.lightslategray

    global.starColor = global.selectedColor
    global.starColor2 = global.selectedColor2

    global.closureColor = global.selectedColor
    global.closureColor2 = global.selectedColor2

    global.linkColor = global.selectedColor
    global.linkColor2 = global.selectedColor2

    global.setminusColor = global.selectedColor
    global.setminusColor2 = global.selectedColor2

    global.boundaryColor = global.selectedColor
    global.boundaryColor2 = global.selectedColor2

    -- For conversion from math space to screen space
    -- TODO: compute these more automatically
    -- These numbers (weights on inRange and the range itself) have been heavily tweaked
    -- And it makes convergence hard
    -- global.scaleFactor = ?
    -- global.optFn = ensure inRange(global.scaleFactor, 75.0, 150.0)
    global.scaleFactor = 70.0
    -- global.offset = 150.0
}

Colors {
    -- Keenan palette
    Colors.black = rgba(0.0, 0.0, 0.0, 1.0)
    Colors.midnightblue = rgba(0.14, 0.16, 0.52, 1.0)
    Colors.lightslategray = rgba(0.50, 0.51, 0.69, 1.0)
    Colors.silver = rgba(0.71, 0.72, 0.79, 1.0)
    Colors.gainsboro = rgba(0.87, 0.87, 0.87, 1.0)

    Colors.darkgray = rgba(0.1, 0.1, 0.1, 1.0)
    Colors.gray = rgba(0.8, 0.8, 0.8, 1.0)
    Colors.red = rgba(1.0, 0.0, 0.0, 1.0)
    Colors.pink = rgba(1.0, 0.4, 0.7, 1.0)
    Colors.yellow = rgba(1.0, 1.0, 0.0, 1.0)
    Colors.orange = rgba(1.0, 0.6, 0.0, 1.0)
    Colors.lightorange = rgba(1.0, 0.6, 0.0, 0.25)
    Colors.green = rgba(0.0, 1.0, 0.0, 1.0)
    Colors.blue = rgba(0.0, 0.0, 1.0, 1.0)
    Colors.sky = rgba(0.325, 0.718, 0.769, 1.0)
    Colors.lightsky = rgba(0.325, 0.718, 0.769, 0.25)
    Colors.lightblue = rgba(0.0, 0.0, 1.0, 0.25)
    Colors.cyan = rgba(0.0, 1.0, 1.0, 1.0)
    Colors.purple = rgba(0.5, 0.0, 0.5, 1.0)
    Colors.lightpurple = rgba(0.5, 0.0, 0.5, 0.25)
    Colors.white = rgba(1.0, 1.0, 1.0, 1.0)
    Colors.none = rgba(0.0, 0.0, 0.0, 0.0)
    Colors.bluegreen = rgba(0.44, 0.68, 0.60, 1.0)
}

-- TODO: this is going to match Subcomplex too... how to fix that?
SimplicialComplex K {
       -- No longer necessary, as box size is being computed
       -- K.x_offset = ?
       -- K.y_offset = ?

       -- Plugin computes mesh's bbox center and dimensions; Style scales it and adds padding
       K.box_padding = 50.0
       K.center_x = ddg[K.name]["center_x"] * global.scaleFactor
       K.center_y = ddg[K.name]["center_y"] * global.scaleFactor
       K.size_x = ddg[K.name]["size_x"] * global.scaleFactor + K.box_padding
       K.size_y = ddg[K.name]["size_y"] * global.scaleFactor + K.box_padding

       K.shape = Rectangle {
       	       x : K.center_x
	       y : K.center_y
	       w : K.size_x
	       h : K.size_y
	       rotation : 0.0
	       color : Colors.gainsboro
	       strokeColor : Colors.black
	       strokeWidth : global.sc_rect_stroke
       }

       K.padding = 25.0

       K.text = Text {
	 x : K.shape.x - K.shape.w / 2.0 + K.padding
	 y : K.shape.y - K.shape.h / 2.0 + K.padding
	 string : K.label
	 rotation : 0.0
	 color : Colors.black
       }

       K.labelFn = encourage centerLabel(K.shape, K.text)

       K.layerTextFn = K.text above K.shape

       -- Expression label
       K.expr_padding = 25.0

       K.const_text = Text {
       	 x : K.shape.x 
       	 y : K.shape.y - (K.size_y / 2.0) - K.expr_padding
       	 string : "\\text{ }"
       	 rotation : 0.0
       	 color : global.starColor
       }

       K.const_layerFn = K.const_text above K.shape
}

-- Label SimplicialSets
-- TODO: this currently seems to be too general
SimplicialSet S
where SubsetOf(S, K)
with SimplicialComplex K {
     S.val = 0.0 -- TODO: need to make a fake field so the label can be inserted
     override K.const_text.string = S.label -- Just label one thing
}

-- TODO: this generates a (K1, K2) and (K2, K1) match
SimplicialComplex K1; SimplicialComplex K2 {
	 LOCAL.padding = 30.0

	 -- TODO: improve this for rectangles by not just using the x size
	 LOCAL.overlapFn = ensure disjoint(K1.shape, K2.shape, LOCAL.padding)
	 LOCAL.alignFn = ensure sameHeight(K1.shape, K2.shape)
	 -- LOCAL.distFn = ensure distBetween(K1.shape, K2.shape, LOCAL.padding)
}

Vertex v 
where InVS(v, K)
with SimplicialComplex K {
       v.xpos = ddg[v.name]["x"] * global.scaleFactor
       v.ypos = ddg[v.name]["y"] * global.scaleFactor

       v.shape = Circle { 
         x : v.xpos -- avoid "x <- f(x)" in override
	 y : v.ypos
         r : 0.0
	 color : Colors.black
	 strokeWidth : 0.0
       }

       -- NOTE: by default, this starts with an empty string, so we only label user-declared vertices
       v.text = Text {
	 x : v.shape.x + global.padding
	 y : v.shape.y + global.padding
	 string : "\\text{ }" 
	 -- string : " " -- TODO: the frontend does not deal with empty strings well! Doesn't seem to generate a label with dimensions. See above for how to get around this
	 rotation : 0.0
	 color : v.shape.color
       }

       v.layerFnShape = v.shape above K.shape
       v.layerFnText = v.text above K.shape
       -- v.posFn = ensure onCanvas(v.shape)
       -- v.posFn = encourage center(v.shape)
}

-- Style a distinguished vertex (only if it's a result)
Vertex v
where DeclaredV(v); InVS(v, K); Result(v)
with SimplicialComplex K {
      -- Don't label the vertex because then we need to position it...
      -- override v.text.string = v.label

      override v.shape.r = global.selectedRadius
      override v.shape.color = global.closureColor

      v.offset = 10.0
      v.labelCloseFn = encourage near(v.text, v.shape, v.offset)

      /*
       -- Optimize the label padding, only for the distinguished vertex
      v.padding_x = ?
      v.padding_y = ?
      override v.text.x = v.shape.x + v.padding_x
      override v.text.y = v.shape.y + v.padding_y

      v.offset = 30.0
      -- This is trying to place the labels but it's very slow, goes from 40s to 3min
      v.labelInComplexFn = ensure contains(K.shape, v.text)
      -- Label's color might need to be programmatically set depending on its location

      v.padding_range = 20.0
      v.labelRangeXFn = ensure inRange(v.padding_x, v.shape.x - v.padding_range, v.shape.x + v.padding_range)
      v.labelRangeYFn = ensure inRange(v.padding_y, v.shape.y - v.padding_range, v.shape.y + v.padding_range) */
}

Vertex v; Edge e
where DeclaredV(v); InVS(v, K); InES(e, K)
with SimplicialComplex K {
     LOCAL.offset = 5.0
     -- Make sure the label doesn't overlap with any edge
     -- TODO: this is NaNing
     LOCAL.edgeLabelFn = ensure disjoint(v.text, e.shape, LOCAL.offset)
}

Edge e
where e := MkEdge(v1, v2); InES(e, K)
with Vertex v1; Vertex v2; SimplicialComplex K {
     e.shape = Line { 
     	     startX : v1.shape.x
     	     startY : v1.shape.y
     	     endX : v2.shape.x
     	     endY : v2.shape.y
	     color : Colors.black
	     thickness : global.edgeStroke
     }

     e.layering1 = v1.shape above e.shape
     e.layering2 = v2.shape above e.shape
     e.layering3 = e.shape above K.shape
}

-- Style a distinguished edge (only if it's declared to be a result)
Edge e
where DeclaredE(e); e := MkEdge(v1, v2); InES(e, K); Result(e)
with Vertex v1; Vertex v2; SimplicialComplex K {
     override e.shape.thickness = global.selectedEdgeStroke
     override e.shape.color = global.closureColor

     e.text = Text {
       x : average(e.shape.startX, e.shape.endX) + global.padding
       y : average(e.shape.startY, e.shape.endY) + global.padding
       -- string : e.label
       string : "\\text{ }" 
       rotation : 0.0
       color : e.shape.color
     }

     e.layerFnText = e.text above K.shape
}

Face f -- 255,552 substitutions = 22 e * 22 e * 22 e * 12 f * 2 sc
where f := MkFace(e1, e2, e3); InFS(f, K)
with Edge e1; Edge e2; Edge e3; SimplicialComplex K {
     f.color = Colors.silver

     f.shape = Curve { 
     	     pathData : triangle(e1.shape, e2.shape, e3.shape)
	     strokeWidth : 0.0
	     fill : f.color
	     color : f.color
	     rotation : 0.0
     }

     f.layeringShape = f.shape above K.shape
}

-- Style and label a distinguished face
Face f
where DeclaredF(f); InFS(f, K)
with SimplicialComplex K {
     -- Need to pick a color that doesn't "override" the selected edges and vertices!
     override f.shape.fill = global.selectedFaceColor
     override f.shape.color = global.selectedFaceColor

     -- f.text = Text {
     --   x : ?
     --   y : ?
     --   string : f.label
     --   rotation : 0.0
     --   color : f.shape.color
     -- }

     -- f.layerFnText = f.text above K.shape
}

-- Relative layerings within a simplicial complex
Vertex v; Edge e; Face f
where InVS(v, K); InES(e, K); InFS(f, K)
with SimplicialComplex K {
      LOCAL.textLayering1 = v.text above f.shape 
      LOCAL.textLayering2 = v.text above e.shape
}

-- Style a SimplicialSet union of vertices (TODO: figure out how to match more generically)
SimplicialSet S
where SubsetOf(S, K); S := Union(v1, v2); Result(S)
with SimplicialComplex K; Vertex v1; Vertex v2 {
     override v1.shape.r = global.selectedRadius
     override v1.shape.color = global.selectedColor

     override v2.shape.r = global.selectedRadius
     override v2.shape.color = global.selectedColor
}

-- Style a SimplicialSet union (of edge and face only! not in general)
SimplicialSet S
where SubsetOf(S, K); S := Union(e, f); Result(S)
with SimplicialComplex K; Edge e; Face f {
     override e.shape.color = global.selectedColor
     override f.shape.color = global.selectedColor
     override f.shape.fill = global.selectedColor
}

------------------ Things in a closure of a vertex 
-- (we know it's the same vertex, so we need to write a match that uses the same variable)

Vertex v
where InVS(v, C); C := Closure(v); Result(C)
with Subcomplex C {
     override v.shape.r = global.selectedRadius
     override v.shape.color = global.closureColor
     -- This is being selected; it's just too dark to tell...
}

------------------ Things in a closure of a subset

Vertex v
where InVS(v, C); C := Closure(S); Result(C)
with Subcomplex C; SimplicialSet S {
     override v.shape.r = global.selectedRadius
     override v.shape.color = global.closureColor
}

Edge e
where InES(e, C); C := Closure(S); Result(C)
with Subcomplex C; SimplicialSet S {
     -- TODO: edge positions might look weird due to layering with faces?
      override e.shape.thickness = global.selectedEdgeStroke
      override e.shape.color = global.closureColor
}

-- Case when the edge is in its own closure... TODO fix this matching semantics so the variable substitution w/ subtyping works above
Edge e
where InES(e, C); C := Closure(e); Result(C)
with Subcomplex C {
      override e.shape.thickness = global.selectedEdgeStroke
      override e.shape.color = global.closureColor
}

Face f
where InFS(f, C); C := Closure(S); Result(C)
with Subcomplex C; SimplicialSet S {
      override f.shape.fill = global.closureColor2
      override f.shape.color = global.closureColor2
}

------------------ Things in a subset that result from a star of a subset (vertex or subset)

Vertex v
where InVS(v, S); S := Star(i); SubsetOf(S, K); Result(S)
with SimplicialSet S; SimplicialComplex K; SimplicialSet i {
     override v.shape.r = global.selectedRadius
     override v.shape.color = global.starColor
}

Edge e
where InES(e, S); S := Star(i); SubsetOf(S, K); Result(S)
with SimplicialSet S; SimplicialComplex K; SimplicialSet i {
      override e.shape.thickness = global.selectedThickness
      override e.shape.color = global.starColor
}

Face f
where InFS(f, S); S := Star(i); SubsetOf(S, K); Result(S)
with SimplicialSet S; SimplicialComplex K; SimplicialSet i {
      override f.shape.fill = global.starColor2
      override f.shape.color = global.starColor2
}

------------------ Things in a link of a subset

Vertex v
where InVS(v, S2); S2 := Link(S1); Result(S2)
with SimplicialSet S2; SimplicialSet S1 {
     override v.shape.r = global.selectedRadius
     override v.shape.color = global.linkColor
}

Edge e
where InES(e, S2); S2 := Link(S1); Result(S2)
with SimplicialSet S2; SimplicialSet S1 {
      override e.shape.thickness = global.selectedThickness
      override e.shape.color = global.linkColor
}

Face f
where InFS(f, S2); S2 := Link(S1); Result(S2)
with SimplicialSet S2; SimplicialSet S1 {
      override f.shape.fill = global.linkColor2
      override f.shape.color = global.linkColor2
}

------------------ Things in setminus of two subsets

Vertex v
where InVS(v, S3); S3 := SetMinus(S1, S2); Result(S3)
with SimplicialSet S3; SimplicialSet S2; SimplicialSet S1 {
     override v.shape.r = global.selectedRadius
     override v.shape.color = global.setminusColor
}

Edge e
where InES(e, S3); S3 := SetMinus(S1, S2); Result(S3)
with SimplicialSet S3; SimplicialSet S2; SimplicialSet S1 {
      override e.shape.thickness = global.selectedThickness
      override e.shape.color = global.setminusColor
}

Face f
where InFS(f, S3); S3 := SetMinus(S1, S2); Result(S3)
with SimplicialSet S3; SimplicialSet S2; SimplicialSet S1 {
      override f.shape.fill = global.setminusColor2
      override f.shape.color = global.setminusColor2
}

------------------ Things in boundary of a subcomplex

Vertex v
where InVS(v, S); S := Boundary(C); Result(S)
with SimplicialSet S; SimplicialComplex C {
     override v.shape.r = global.selectedRadius
     override v.shape.color = global.boundaryColor
}

Edge e
where InES(e, S); S := Boundary(C); Result(S)
with SimplicialSet S; SimplicialComplex C {
      override e.shape.thickness = global.selectedThickness
      override e.shape.color = global.boundaryColor
}

Face f
where InFS(f, S); S := Boundary(C); Result(S)
with SimplicialSet S; SimplicialComplex C {
      override f.shape.fill = global.boundaryColor2
      override f.shape.color = global.boundaryColor2
}

-------------------

-- Only label the (last) result of an operation
Object e
with SimplicialComplex K
where Result(e) {
      override K.const_text.string = e.label
}

Edge e; Face f {
     LOCAL.layering = e.shape above f.shape
}

-- Try to position the vertices to be inside the bbox
-- Should this go in the vertex selector?
-- Vertex v
-- where InVS(v, K)
-- with SimplicialComplex K {
     -- No longer necessary, as box size is being computed
     -- override v.shape.x = v.xpos + K.x_offset
     -- override v.shape.y = v.ypos + K.y_offset

     -- v.inSCFn = ensure contains(v.shape, K.shape)
-- }
